#ifndef _TEST_C_
#define _TEST_C_

#include "serverfunction.h"

//
void after_write(uv_write_t* req, int status) {
    write_req_t* wr;
    uv_err_t err;

    wr = (write_req_t *) req;
    if (wr->buf.base) {
        free(wr->buf.base);
        wr->buf.base = 0x0;
    }

    if ( wr ) {
        free(wr);
        wr = 0x0;
    }

    if ( status == 0 ) {
        return;
    }

    err = uv_last_error(req->handle->loop);
    if ( err.code == UV_ECANCELED ) {
        return;
    }

    fprintf(stderr, "uv_write after error:%s\n", uv_strerror(err));
    uv_close((uv_handle_t*)req->handle, on_close);

}

void after_shutdown(uv_shutdown_t *req, int status) {
        uv_close((uv_handle_t*) req->handle, on_close);
        printf("after_shutdown :%s\n", "shutdown");
        if( req) {
            free(req);
            req = 0x0;
        }

}

void after_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {

    if ( nread > 0) {
        int ret = parse_recved_data(handle, buf.base, (uint32_t)nread);
        if ( ret ) {
            //TODO
        }
	request_body_t *reqbody = (request_body_t*) handle->data;
        if (buf.base && reqbody->bufflen <= 0) {
            free(buf.base);
            buf.base = 0x0;
        }
	return;
    } else {
        if ( buf.base) {
            free(buf.base);
            buf.base = 0x0;
        }

        uv_err_t err = uv_last_error(handle->loop);

        if ( nread == 0 || err.code == UV_EOF ) {
            printf("after_read uv error code: %d\n", err.code);
            uv_close((uv_handle_t*)handle, on_close);
            return;
        }

        if ( err.code == UV_ECONNRESET || UV_EPIPE == err.code) {
            uv_close((uv_handle_t*)handle, on_close);
            return;
        }

        if (err.code == UV_ETIMEDOUT) {
            uv_close((uv_handle_t*)handle, on_close);
            return;
        }

        fprintf(stderr, "after_read error: %s\n", uv_err_name(err));
        uv_shutdown_t *req = (uv_shutdown_t*)malloc(sizeof(uv_shutdown_t));
        uv_shutdown(req, handle, after_shutdown);
        return;
    }

}

void on_close(uv_handle_t* peer) {
    request_body_t *reqbody = (request_body_t *)peer->data;
    if (reqbody->header != NULL) {
        printf("reqbody init addr = %p, after addr = %p\n", reqbody->header, &reqbody->companyid);
        free(reqbody);
        reqbody = 0x00;
    }

    if (peer) {
        free(peer);
        peer = 0x0;
    }
}

static uv_buf_t echo_alloc(uv_handle_t* handle, size_t suggested_size) {
    uv_buf_t buf;
    buf.base = (char *)malloc(suggested_size * sizeof(char));
    buf.len = suggested_size;
    ASSERT(buf.base != NULL);
    return buf;
}

void on_connection(uv_stream_t *server, int status) {
    uv_stream_t* stream;
    int r;

    if (status != 0) {
        fprintf(stderr, "Connected error, errcode:%d\n", uv_last_error(server->loop).code);
    }

    ASSERT(status == 0);

    switch(server->type) {
        case UV_TCP:
            stream = (uv_stream_t *) malloc(sizeof(uv_tcp_t));
            ASSERT(stream != NULL);
            memset(stream, 0x00, sizeof(uv_tcp_t));
            r = uv_tcp_init(server->loop, (uv_tcp_t*)stream);
        break;
        default:
            ASSERT( 0 && "Bad serverType");
            abort();

    }

    request_body_t *reqbody;
    int reqbodylen = sizeof(request_body_t) + sizeof(char)* CAPACITY_SIZE;
    reqbody = (request_body_t *) malloc(reqbodylen);
    ASSERT(reqbody != NULL);
    memset(reqbody, 0x00, reqbodylen);

    reqbody->companyid = 0;
    reqbody->capacity = CAPACITY_SIZE;
    reqbody->bufflen = 0;
    reqbody->header = (void *)reqbody;

    stream->data = (void *)reqbody;
    r = uv_accept(server, stream);
    ASSERT( r == 0);
    struct sockaddr_in name;
    char *cliIP = 0x0;
    uint16_t cliPort = 0;
    int namelen = sizeof(struct sockaddr);
    uv_tcp_getpeername((uv_tcp_t*)stream, (struct sockaddr *)&name, &namelen);
    if ( ( (struct sockaddr*)&name)->sa_family == AF_INET) {
        cliIP = inet_ntoa( name.sin_addr );
        cliPort = ntohs( name.sin_port);
    }
    else {
        cliIP = "<unknown>";
    }

    char logmsg[128];
    const char *logfmt = "client ip %s:%d";
    memset(logmsg, 0x00, sizeof(logmsg));
    snprintf(logmsg, sizeof(logmsg) - 1, logfmt, cliIP, cliPort);
    do_server_log(g_mysql_conn, "new_conn", logmsg);

    r = uv_read_start(stream, echo_alloc, after_read);
    ASSERT(r == 0);
}


void on_server_close(uv_handle_t* handle) {
    ASSERT(handle == server);
}

int tcp4_server_main(int port, uv_loop_t *rloop, uv_tcp_t* rserver) {
    struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", port);
    int r;

    r = uv_tcp_init(rloop, rserver);
    if (r) {
        fprintf(stderr, "Socket created error!\n");
        return -1;

    }

    r = uv_tcp_bind(rserver, addr);
    if (r) {
        fprintf(stderr, "Bind tcp error!\n");
        return -1;
    }

    uv_stream_t* uvStream = (uv_stream_t*)rserver;
    uvStream->type = UV_TCP;
    r = uv_listen( uvStream, SOMAXCONN, on_connection);
    if (r) {
        fprintf(stderr, "Listen error: %s\n", uv_err_name(uv_last_error(rloop)));
        return -1;
    }

    return 0;
}

#endif
